package com.cui.project.recommend.service.impl;

import com.api.common.model.entity.InterfaceInfo;
import com.api.common.model.entity.InterfaceInfoLog;
import com.api.common.model.entity.UserInterfaceFavorite;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cui.project.mapper.InterfaceInfoMapper;
import com.cui.project.mapper.UserInterfaceFavoriteMapper;
import com.cui.project.recommend.service.PlacementService;
import com.cui.project.mapper.InterfaceInfoLogMapper;
import com.cui.project.recommend.model.dto.PlacementItem;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;


/**
 * 智能运营位（趋势/飙升/新品）
 *
 * 运行逻辑：
 *  1）趋势榜（trend）：近7天成功调用与收藏事件做 EMA（α=0.3），按热度降序 TopK
 *  2）飙升榜（surge）：最近24h 与 前24h 的调用次数做相对涨幅 (late-early)/(early+5)，降序 TopK
 *  3）新品（new）：按 interface_info.createTime 筛选近14天，时间倒序 TopK
 * 分析用了那些算法：
 *  趋势榜（Trend）：EMA 对近 7 天成功调用 + 收藏事件求平滑热度，取 Top-K。
 *  飙升榜（Surge）：两窗口相对涨幅
 *  比较近 24h（late）与前 24h（early）计数的增幅：
 *      surge = (late - early) / (early + 5)（+5 平滑项避免分母过小导致噪声）。
 *  新品（New）：按 interface_info.createTime 近 14 天筛选并倒序。
 */
@Service
@RequiredArgsConstructor
public class PlacementServiceImpl implements PlacementService {

    private final InterfaceInfoLogMapper logMapper;
    private final InterfaceInfoMapper infoMapper;
    private final UserInterfaceFavoriteMapper favMapper;

    /**
     * 运营位主入口
     * 运行逻辑：
     * - 计算 trend/surge/new 三类列表，各取 eachTopK
     * - 合并输出（按 slot 标识）
     */
    @Override
    public List<PlacementItem> placementsForUser(Long userId, int eachTopK) { // userId 目前未用，可扩展“为你推荐位”
        Instant now = Instant.now(); // 当前
        final Instant t7d  = now.minus(7, ChronoUnit.DAYS); // 7天前
        final Instant t48h = now.minus(48, ChronoUnit.HOURS); // 48小时前
        final Instant t24h = now.minus(24, ChronoUnit.HOURS); // 24小时前
        final Instant t14d = now.minus(14, ChronoUnit.DAYS); // 14天前

        // —— trend：近7天 EMA（成功调用 + 收藏）——
        List<InterfaceInfoLog> logs7raw = logMapper.selectList( // 查7天内日志
                new LambdaQueryWrapper<InterfaceInfoLog>().ge(InterfaceInfoLog::getCreateTime, Date.from(t7d))
        );
        List<InterfaceInfoLog> logs7 = new ArrayList<InterfaceInfoLog>(); // 成功调用集合
        for (InterfaceInfoLog l : logs7raw) if (l.getCode()!=null && l.getCode()==200) logs7.add(l); // 过滤 code=200
        Collections.sort(logs7, new Comparator<InterfaceInfoLog>() { // 时间升序
            @Override public int compare(InterfaceInfoLog o1, InterfaceInfoLog o2) {
                return o1.getCreateTime().compareTo(o2.getCreateTime());
            }
        });
        Map<Long, Double> ema = new HashMap<Long, Double>(); // EMA 热度表
        double alpha = 0.3; // EMA 平滑因子
        for (InterfaceInfoLog l : logs7) { // 遍历成功调用
            long iid = l.getInterface_info_id(); // 接口ID
            Double prev = ema.get(iid); // 之前热度
            ema.put(iid, (prev == null ? 0.0 : prev)*(1-alpha) + alpha*1.0); // 计1次
        }
        List<UserInterfaceFavorite> fav7 = favMapper.selectList(null); // 取收藏（全量后过滤）
        for (UserInterfaceFavorite f : fav7){ // 遍历收藏
            if (f.getStatus() != null && f.getStatus() == 1 && // 有效收藏
                    (f.getUpdateTime()==null || f.getUpdateTime().toInstant().isAfter(t7d))){ // 近7天新增/更新
                long iid = f.getInterfaceInfoId(); // 接口ID
                Double prev = ema.get(iid); // 之前热度
                ema.put(iid, (prev == null ? 0.0 : prev)*(1-alpha) + alpha*1.0); // 计1次
            }
        }
        List<Map.Entry<Long, Double>> trendList = new ArrayList<Map.Entry<Long, Double>>(ema.entrySet()); // 热度条目
        Collections.sort(trendList, new Comparator<Map.Entry<Long, Double>>() { // 按热度降序
            @Override public int compare(Map.Entry<Long, Double> o1, Map.Entry<Long, Double> o2) {
                return Double.compare(o2.getValue(), o1.getValue());
            }
        });
        List<PlacementItem> trend = new ArrayList<PlacementItem>(); // 趋势榜
        for (int i=0;i<trendList.size() && i<eachTopK;i++){ // 截断 TopK
            Map.Entry<Long, Double> e = trendList.get(i); // 热度项
            trend.add(toPlacement("trend", e.getKey(), "近7天热度指数", e.getValue())); // 组装 DTO
        }

        // surge：近24h 相比前24h 的涨幅（仅成功调用）
        List<InterfaceInfoLog> logs48raw = logMapper.selectList(
                new LambdaQueryWrapper<InterfaceInfoLog>().ge(InterfaceInfoLog::getCreateTime, Date.from(t48h))
        );
        Map<Long, Integer> early = new HashMap<Long, Integer>(); // 前24h 次数
        Map<Long, Integer> late  = new HashMap<Long, Integer>(); // 近24h 次数
        for (InterfaceInfoLog l : logs48raw){ // 遍历日志
            if (l.getCode()==null || l.getCode()!=200) continue; // 非成功调用忽略
            if (l.getCreateTime().toInstant().isBefore(t24h)){ // 属于“前24小时”
                Integer old = early.get(l.getInterface_info_id()); // 旧计数
                early.put(l.getInterface_info_id(), old == null ? 1 : old + 1); // +1
            } else { // 属于“最近24小时”
                Integer old = late.get(l.getInterface_info_id()); // 旧计数
                late.put(l.getInterface_info_id(), old == null ? 1 : old + 1); // +1
            }
        }
        List<PlacementItem> surge = new ArrayList<PlacementItem>(); // 飙升榜
        for (Long iid : late.keySet()){ // 对所有最近24h出现过的接口计算涨幅
            double e = early.get(iid) == null ? 0.0 : early.get(iid).doubleValue(); // 前24h 次数
            double m = late.get(iid)  == null ? 0.0 : late.get(iid).doubleValue();  // 近24h 次数
            double inc = (m - e) / (e + 5.0); // 涨幅（+5 平滑避免分母过小）
            surge.add(toPlacement("surge", iid, "24小时飙升", inc)); // 组装 DTO
        }
        Collections.sort(surge, new Comparator<PlacementItem>() { // 按涨幅降序
            @Override public int compare(PlacementItem o1, PlacementItem o2) {
                return Double.compare(o2.getScore(), o1.getScore());
            }
        });
        if (surge.size() > eachTopK) surge = surge.subList(0, eachTopK); // 截断 TopK

        // new：近14天新接口（interface_info.createTime）
        List<InterfaceInfo> allInfos = infoMapper.selectList(null); // 全量接口
        List<InterfaceInfo> news = new ArrayList<InterfaceInfo>(); // 新品列表
        for (InterfaceInfo i : allInfos){ // 遍历接口
            if (i.getCreateTime()!=null && i.getCreateTime().toInstant().isAfter(t14d)){ // 近14天创建
                news.add(i); // 加入新品
            }
        }
        Collections.sort(news, new Comparator<InterfaceInfo>() { // 按创建时间降序
            @Override public int compare(InterfaceInfo o1, InterfaceInfo o2) {
                return o2.getCreateTime().compareTo(o1.getCreateTime());
            }
        });
        if (news.size() > eachTopK) news = news.subList(0, eachTopK); // 截断 TopK
        List<PlacementItem> newList = new ArrayList<PlacementItem>(); // 新品位 DTO
        for (InterfaceInfo i : news){ // 遍历新品
            newList.add(toPlacement("new", i.getId(), "全新上线/近期发布", 1.0)); // 组装 DTO（分数用1.0占位）
        }

        // —— 合并三类位 ——
        List<PlacementItem> all = new ArrayList<PlacementItem>(); // 合并列表
        all.addAll(trend); // 加入趋势
        all.addAll(surge); // 加入飙升
        all.addAll(newList); // 加入新品
        return all; // 返回综合结果（前端按 slot 分组展示）
    }

    // 小工具：快速构造 PlacementItem
    private static PlacementItem toPlacement(String slot, Long interfaceId, String subtitle, double score){ // 构造运营位 DTO
        PlacementItem p = new PlacementItem(); // 新对象
        p.setSlot(slot); // 槽位标识：trend/surge/new
        p.setInterfaceId(interfaceId); // 接口ID
        p.setSubtitle(subtitle); // 展示副标题
        p.setScore(score); // 排序分
        return p; // 返回
    }
}